package downloader

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"github.com/user/go-capcut/internal/util"
)

// Downloader 下载器接口
type Downloader interface {
	DownloadVideo(videoURL, draftName, materialName string) (string, error)
	DownloadAudio(audioURL, draftName, materialName string) (string, error)
	DownloadImage(imageURL, draftName, materialName string) (string, error)
}

// FileDownloader 文件下载器实现
type FileDownloader struct {
	MaxRetries int
	Timeout    time.Duration
}

// NewFileDownloader 创建新的文件下载器
func NewFileDownloader() *FileDownloader {
	return &FileDownloader{
		MaxRetries: 3,
		Timeout:    180 * time.Second,
	}
}

// DownloadVideo 下载视频到指定目录
func (d *FileDownloader) DownloadVideo(videoURL, draftName, materialName string) (string, error) {
	// 确保目录存在
	videoDir := filepath.Join(draftName, "assets", "video")
	if err := createDirectoryIfNotExists(videoDir); err != nil {
		return "", err
	}

	// 生成本地文件路径
	fileExt := util.GetFileExtension(videoURL)
	if fileExt == "" {
		fileExt = ".mp4" // 默认扩展名
	}

	localPath := filepath.Join(videoDir, materialName+fileExt)

	// 下载文件
	if err := d.downloadFile(videoURL, localPath); err != nil {
		return "", err
	}

	return localPath, nil
}

// DownloadAudio 下载音频到指定目录
func (d *FileDownloader) DownloadAudio(audioURL, draftName, materialName string) (string, error) {
	// 确保目录存在
	audioDir := filepath.Join(draftName, "assets", "audio")
	if err := createDirectoryIfNotExists(audioDir); err != nil {
		return "", err
	}

	// 生成本地文件路径
	fileExt := util.GetFileExtension(audioURL)
	if fileExt == "" {
		fileExt = ".mp3" // 默认扩展名
	}

	localPath := filepath.Join(audioDir, materialName+fileExt)

	// 下载文件
	if err := d.downloadFile(audioURL, localPath); err != nil {
		return "", err
	}

	return localPath, nil
}

// DownloadImage 下载图片到指定目录
func (d *FileDownloader) DownloadImage(imageURL, draftName, materialName string) (string, error) {
	// 确保目录存在
	imageDir := filepath.Join(draftName, "assets", "image")
	if err := createDirectoryIfNotExists(imageDir); err != nil {
		return "", err
	}

	// 生成本地文件路径
	fileExt := util.GetFileExtension(imageURL)
	if fileExt == "" {
		fileExt = ".png" // 默认扩展名
	}

	localPath := filepath.Join(imageDir, materialName+fileExt)

	// 下载文件
	if err := d.downloadFile(imageURL, localPath); err != nil {
		return "", err
	}

	return localPath, nil
}

// downloadFile 下载文件到本地
func (d *FileDownloader) downloadFile(url, localFilename string) error {
	// 检查是否是本地文件路径
	if fileExists(url) {
		// 是本地文件，直接复制
		directory := filepath.Dir(localFilename)

		// 创建目标目录（如果不存在）
		if directory != "" && !fileExists(directory) {
			if err := os.MkdirAll(directory, os.ModePerm); err != nil {
				return fmt.Errorf("创建目录失败: %v", err)
			}
		}

		// 复制文件
		srcFile, err := os.Open(url)
		if err != nil {
			return fmt.Errorf("打开源文件失败: %v", err)
		}
		defer srcFile.Close()

		dstFile, err := os.Create(localFilename)
		if err != nil {
			return fmt.Errorf("创建目标文件失败: %v", err)
		}
		defer dstFile.Close()

		if _, err := io.Copy(dstFile, srcFile); err != nil {
			return fmt.Errorf("复制文件失败: %v", err)
		}

		return nil
	}

	// 远程URL，下载文件
	var lastErr error
	for i := 0; i < d.MaxRetries; i++ {
		// 创建HTTP客户端
		client := &http.Client{
			Timeout: d.Timeout,
		}

		// 发送GET请求
		resp, err := client.Get(url)
		if err != nil {
			lastErr = fmt.Errorf("HTTP请求失败: %v", err)
			continue
		}
		defer resp.Body.Close()

		// 检查响应状态码
		if resp.StatusCode != http.StatusOK {
			lastErr = fmt.Errorf("HTTP响应状态码非200: %d", resp.StatusCode)
			continue
		}

		// 创建目标目录（如果不存在）
		directory := filepath.Dir(localFilename)
		if directory != "" && !fileExists(directory) {
			if err := os.MkdirAll(directory, os.ModePerm); err != nil {
				return fmt.Errorf("创建目录失败: %v", err)
			}
		}

		// 创建目标文件
		out, err := os.Create(localFilename)
		if err != nil {
			return fmt.Errorf("创建文件失败: %v", err)
		}
		defer out.Close()

		// 写入文件
		if _, err = io.Copy(out, resp.Body); err != nil {
			lastErr = fmt.Errorf("写入文件失败: %v", err)
			continue
		}

		// 下载成功
		return nil
	}

	return fmt.Errorf("下载失败，已重试%d次: %v", d.MaxRetries, lastErr)
}

// createDirectoryIfNotExists 如果目录不存在则创建
func createDirectoryIfNotExists(dirPath string) error {
	if !fileExists(dirPath) {
		return os.MkdirAll(dirPath, os.ModePerm)
	}
	return nil
}

// fileExists 检查文件或目录是否存在
func fileExists(path string) bool {
	_, err := os.Stat(path)
	return !os.IsNotExist(err)
}
